package org.example.old.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ConverterUtils;
import com.alibaba.excel.util.ListUtils;
import lombok.extern.slf4j.Slf4j;
import org.example.old.dto.CellDataReadDemoData;
import org.example.old.dto.SysDto;
import org.example.old.impl.SysServiceImpl;
import org.example.old.service.SysService;

import java.util.*;
import java.util.stream.Collectors;


/**
 * DemoDataListener不能被spring管理，要每次读取excel都要new
 * 然后里面用到spring可以构造方法传进去
 */
@Slf4j
public class DemoDataListener implements ReadListener<SysDto> {

    /**
     * 每隔5条存储数据库，实际使用中可以100，然后清理list，方便内存回收
     */
    private static final int BATCH_COUNT= 3000;

    /**
     * 缓存的数据
     */
    private List<SysDto> list = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);


    private SysService sysService;

    public DemoDataListener(){
        sysService = new SysServiceImpl();
    }


    public DemoDataListener(SysService sysService){
        this.sysService = sysService;
    }



    /**
     * 这个每一条数据解析都会来调用
     * @param sysDto
     * @param analysisContext
     */
    @Override
    public void invoke(SysDto sysDto, AnalysisContext analysisContext) {
        list.add(sysDto);
        // 达到BATCH_COUNT了，需要去存储一次数据库，防止数据几万条数据在内存，容易OOM
        if(list.size() >= BATCH_COUNT){
            // 走业务逻辑
            savaData();
            // 清理list
            list = new ArrayList<>(BATCH_COUNT);
        }
    }


    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        savaData();
    // 保存数据，确保最后遗留的数据也存储到数据库
        System.out.println("所有数据解析完成");
    }

    private void savaData(){
        System.out.println(list.size()+"条数据，开始存储数据库");
        sysService.addUserList(list);
        System.out.println("存储数据库成功");
    }



    /**
     * 会一行行的返回头
     * @param headMap
     * @param context
     */
    @Override
    public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
        System.out.println("解析到一条头数据："+headMap.toString());
        // 如果想转成Map<Integer,String>
        // 方案1：不要 implements ReadListener 而是extends AnalysisEventListener
        // 方案2： 调用ConverterUtils.converToStringMap(headMap,context)自动会转换
        Map<Integer, String> map = ConverterUtils.convertToStringMap(headMap,context);
        Collection<String> values =  map.values();

        list.add((SysDto) values.stream().collect(Collectors.toList()));
        // 达到BATCH_COUNT了，需要去存储一次数据库，防止数据几万条数据在内存，容易OOM
        if(list.size() >= BATCH_COUNT){
            // 走业务逻辑
            savaData();
            // 清理list
            list = new ArrayList<>(BATCH_COUNT);
        }
    }


    @Override
    public void extra(CellExtra extra, AnalysisContext context) {
        System.out.println("读取到了一条额外信息："+extra.toString());
        switch (extra.getType()){
            case COMMENT:
                System.out.println("额外信息是批注，在rowIndex"+extra.getRowIndex()+
                        ";columnIndex"+ extra.getColumnIndex()+";,内容是:"+extra.getText()
                        );
                break;
            case HYPERLINK:
                if ("Sheet1!A1".equals(extra.getText())) {
                    log.info("额外信息是超链接,在rowIndex:{},columnIndex;{},内容是:{}", extra.getRowIndex(),
                            extra.getColumnIndex(), extra.getText());
                } else if ("Sheet2!B2".equals(extra.getText())) {
                    log.info(
                            "额外信息是超链接,而且覆盖了一个区间,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{},"
                                    + "内容是:{}",
                            extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(),
                            extra.getLastColumnIndex(), extra.getText());
                } else {
//                    Assert.fail("Unknown hyperlink!");
                    System.out.println("Unknown hyperlink!");
                }
                break;
            case MERGE:
                log.info(
                        "额外信息是超链接,而且覆盖了一个区间,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{}",
                        extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(),
                        extra.getLastColumnIndex());
                break;
            default:
        }
    }

    /**
     * 数据转换异常，获取其他异常下会调用本接口，抛出异常则停止读取，如果这里不抛出异常，则继续读取下一行
     * @param exception
     * @param context
     * @throws Exception
     */
    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        log.info("解析失败，但继续解析下一行：{}",exception.getMessage());
        // 如果是某一个单元格转换异常，能获取到具体行号
        // 如果要获取头的信息，配置invokeheadMap使用
        if(exception instanceof ExcelDataConvertException){
            ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;
            log.info("第{}行，第几列解析异常，数据为：{}",excelDataConvertException.getRowIndex(),excelDataConvertException.getColumnIndex(),excelDataConvertException.getCellData());

        }

    }















}
